/**
 * Software License, Version 1.0
 * 
 * Copyright 2003 The Trustees of Indiana University.  All rights reserved.
 * 
 *
 *Redistribution and use in source and binary forms, with or without 
 *modification, are permitted provided that the following conditions are met:
 *
 *1) All redistributions of source code must retain the above copyright notice,
 * the list of authors in the original source code, this list of conditions and
 * the disclaimer listed in this license;
 *2) All redistributions in binary form must reproduce the above copyright 
 * notice, this list of conditions and the disclaimer listed in this license in
 * the documentation and/or other materials provided with the distribution;
 *3) Any documentation included with all redistributions must include the 
 * following acknowledgement:
 *
 *"This product includes software developed by the Community Grids Lab. For 
 * further information contact the Community Grids Lab at 
 * http://communitygrids.iu.edu/."
 *
 * Alternatively, this acknowledgement may appear in the software itself, and 
 * wherever such third-party acknowledgments normally appear.
 * 
 *4) The name Indiana University or Community Grids Lab or NaradaBrokering, 
 * shall not be used to endorse or promote products derived from this software 
 * without prior written permission from Indiana University.  For written 
 * permission, please contact the Advanced Research and Technology Institute 
 * ("ARTI") at 351 West 10th Street, Indianapolis, Indiana 46202.
 *5) Products derived from this software may not be called NaradaBrokering, 
 * nor may Indiana University or Community Grids Lab or NaradaBrokering appear
 * in their name, without prior written permission of ARTI.
 * 
 *
 * Indiana University provides no reassurances that the source code provided 
 * does not infringe the patent or any other intellectual property rights of 
 * any other entity.  Indiana University disclaims any liability to any 
 * recipient for claims brought by any other entity based on infringement of 
 * intellectual property rights or otherwise.  
 *
 *LICENSEE UNDERSTANDS THAT SOFTWARE IS PROVIDED "AS IS" FOR WHICH NO 
 *WARRANTIES AS TO CAPABILITIES OR ACCURACY ARE MADE. INDIANA UNIVERSITY GIVES
 *NO WARRANTIES AND MAKES NO REPRESENTATION THAT SOFTWARE IS FREE OF 
 *INFRINGEMENT OF THIRD PARTY PATENT, COPYRIGHT, OR OTHER PROPRIETARY RIGHTS. 
 *INDIANA UNIVERSITY MAKES NO WARRANTIES THAT SOFTWARE IS FREE FROM "BUGS", 
 *"VIRUSES", "TROJAN HORSES", "TRAP DOORS", "WORMS", OR OTHER HARMFUL CODE.  
 *LICENSEE ASSUMES THE ENTIRE RISK AS TO THE PERFORMANCE OF SOFTWARE AND/OR 
 *ASSOCIATED MATERIALS, AND TO THE PERFORMANCE AND VALIDITY OF INFORMATION 
 *GENERATED USING SOFTWARE.
 */
package cgl.narada.transport.udp;

import java.util.Enumeration;
import java.util.Hashtable;

import cgl.narada.util.ByteUtilities;

/**
 * <p>
 * Title: UDPPingServer
 * </p>
 * <p>
 * Description: Listens a ping message and sends an ack for this ping
 * </p>
 * 
 * @author Beytullah Yildiz
 * @version 1.0
 */

public class UDPPingServer extends Thread {

    private Hashtable ackpinghashtable;

    private boolean udpPingServerDebug = false;

    private long sendackinterval = 200;

    private boolean keepLooping = true;

    private String moduleName = "UDPPingServer: ";

    public UDPPingServer() {
        ackpinghashtable = new Hashtable();
        setName("UDPPingServer");
    }

    public void shutdownServices() {
        keepLooping = false;
        interrupt();
    }

    /**
     * sets debug variable for this class
     * 
     * @param debug
     */
    public void setDebug(boolean debug) {
        udpPingServerDebug = debug;
    }

    /**
     * adds received ping to a vector to be handled
     * 
     * @param link
     *            the link for received ping. it is kept to send acknowledge
     * @param data
     *            received message with a ping
     * @throws Exception
     */
    public void addPing(UDPLink link, byte[] data) throws Exception {
        byte[] time = new byte[9];
        System.arraycopy(data, 0, time, 0, time.length);

        String linkname = link.getLinkId();
        AckPingObject apo = new AckPingObject();
        apo.setLink(link);
        apo.setTime(time);
        ackpinghashtable.put(linkname, apo);

        if (udpPingServerDebug) {
            long pingtime = ByteUtilities.getLong(time);

            System.out.println(moduleName + data[0] + " received ping time "
                + pingtime);
        }

    }

    /**
     * sends an acknowlege to the sender of a ping
     * 
     * @throws Exception
     */
    public void sendAcks() throws Exception {

        Enumeration e = ackpinghashtable.elements();
        while (e.hasMoreElements()) {

            AckPingObject apo = (AckPingObject) e.nextElement();
            UDPLink link = apo.getLink();
            byte[] ackmessage = apo.getTime();
            ackmessage[0] = 105;
            link.sendData(ackmessage);
            ackpinghashtable.remove(link.getLinkId());

            if (udpPingServerDebug) {
                System.out.println(moduleName + ackmessage[0]
                    + " ack_ping is sent for link " + link.getLinkId());
            }
        }
    }

    /**
     * runs thread in a given interval
     */
    public void run() {

        while (keepLooping) {
            try {
                sendAcks();
            } catch (Exception ex) {
                ex.printStackTrace();
            }

            try {
                sleep(sendackinterval);
            } catch (InterruptedException ex1) {
                if (keepLooping) {
                    System.err.println(moduleName + "Error sleeping");
                }
            }
        }
        if (udpPingServerDebug) {
            System.out.println(moduleName + "Shutting down ...");
        }

    }

    /**
     * <p>
     * Title: AckPingObject
     * </p>
     * <p>
     * Description: keeps required information for an acknowledge
     * </p>
     * 
     * @author Beytullah Yildiz
     * @version 1.0
     */
    class AckPingObject {
        UDPLink link;

        byte[] pingtime;

        public void setLink(UDPLink lnk) {
            link = lnk;
        }

        public UDPLink getLink() {
            return link;
        }

        public void setTime(byte[] t) {
            pingtime = t;
        }

        public byte[] getTime() {
            return pingtime;
        }

    }

    public static void main(String[] args) {
    }

}
